package com.tool.app.utils;

import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.tool.app.enums.ViewEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.http.*;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

import java.util.*;

/**
 * XXL-Job任务自动注册器
 * 应用启动时自动注册/更新枚举中定义的所有任务
 */
@Slf4j
@Component
public class ViewJobAutoRegister implements ApplicationRunner {

    @Value("${xxl.job.executor.userName:admin}")
    private String userName;

    @Value("${xxl.job.executor.password:123456}")
    private String password;

    @Value("${xxl.job.admin.addresses}")
    private String adminAddress;

    @Value("${xxl.job.executor.appname}")
    private String appName;

    @Value("${xxl.job.auto.register.enabled:true}")
    private boolean autoRegisterEnabled;

    private final static Map<String, String> cronMap = new HashMap<>();

    {
        //默认每日凌晨执行一次, 需要其他时间在这里修改
        cronMap.put(ViewEnum.DEMO.code, "0 0 * * * ?");
    }

    private final RestTemplate restTemplate;

    public ViewJobAutoRegister(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    @Override
    public void run(ApplicationArguments args) {
        if (!autoRegisterEnabled) {
            log.info("XXL-Job自动注册功能已禁用");
            return;
        }

        try {
            log.info("开始登录XXL-Job...");
            String cookie = login();
            if (cookie == null) {
                log.error("登录XXL-Job失败");
                return;
            }
            log.info("登录XXL-Job成功");
            HttpHeaders headers = new HttpHeaders();
            headers.set("Cookie", cookie);
            headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
            log.info("开始自动注册XXL-Job任务...");
            // 获取执行器ID（必须先确保执行器存在）
            String jobGroupId = getJobGroupId(headers);
            if (jobGroupId == null) {
                saveJobGroupId(headers);
                log.info("获取执行器ID为空, 开始注册执行器");
                jobGroupId = getJobGroupId(headers);
                if (jobGroupId == null) {
                    log.error("注册执行器ID失败，请手动注册执行器 {}" ,appName);
                }
            }

            List<ViewEnum> noJobViewList = getNoJobViewList(jobGroupId, headers);
            for (ViewEnum view : noJobViewList) {
                registerJob(jobGroupId, view, headers);
            }
            log.info("XXL-Job任务自动注册完成");
        } catch (Exception e) {
            log.error("XXL-Job自动注册过程发生异常", e);
        }
    }


    private void saveJobGroupId(HttpHeaders headers ) {
        String url = adminAddress + "/save";
        MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
        params.add("appname", appName);
        params.add("title", "人力资源驾驶舱");
        params.add("addressType", "0");
        params.add("addressList", "");
        HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(params, headers);
       restTemplate.postForEntity(url, request, String.class);
    }


    private String login() {
        // 登录
        String loginUrl = adminAddress + "/login";
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
        params.add("userName", userName);
        params.add("password", password);
        HttpEntity<MultiValueMap<String, String>> loginRequest = new HttpEntity<>(params, headers);
	    try {
		    ResponseEntity<String> response = restTemplate.postForEntity(loginUrl, loginRequest, String.class);
		    // 2. 从响应或 Cookie 中提取
		    if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
		        return response.getHeaders().getFirst("Set-Cookie");
		    }
	    } catch (RestClientException e) {
            log.error("登录xxl-job失败", e);
	    }
	    return null;
    }

    /**
     * 根据应用名称获取执行器ID
     */
    private String getJobGroupId(HttpHeaders headers) {
        MultiValueMap<String, Object> params = new LinkedMultiValueMap<>();
        params.add("start", 0);
        params.add("length", 100);
       // params.add("appname", appName); 人资的xxl带条件搜索报错 , 只把全部查出来
        HttpEntity<Map<String, Object>> request = new HttpEntity<>(headers);
        try {
            String url = adminAddress + "/jobgroup/pageList";
            ResponseEntity<JSONObject> response = restTemplate.postForEntity(url, request, JSONObject.class);
            if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
                JSONObject body = response.getBody();
                JSONArray dataArray = body.getJSONArray("data");
                if (CollUtil.isNotEmpty(dataArray)) {
                    for (Object obj : dataArray) {
                        JSONObject data = (JSONObject) obj;
                        if (appName.equals(data.getString("appname"))) {
                            return data.getString("id");
                        }
                    }
                }
            }
        } catch (Exception e) {
            log.error("获取执行器ID失败", e);
        }
        return null;
    }

    /**
     * 查询任务ID
     */
    private  List<ViewEnum>  getNoJobViewList(String jobGroupId, HttpHeaders headers) {
        MultiValueMap<String,String> params = new LinkedMultiValueMap<>();
        params.add("jobGroup", jobGroupId);
        params.add("triggerStatus", "-1");
        params.add("start", "0");
        params.add("length", "100");

        HttpEntity<MultiValueMap<String,String> > request = new HttpEntity<>(params, headers);
        List<ViewEnum> viewList = new ArrayList<>();
        try {
            String url = adminAddress + "/jobinfo/pageList";
            ResponseEntity<JSONObject> response = restTemplate.postForEntity(url, request, JSONObject.class);
            if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
                JSONObject body = response.getBody();
                JSONArray dataList = body.getJSONArray("data");
                if (CollUtil.isEmpty(dataList)) {
                    //没有就全部需要注册
                    return Arrays.asList(ViewEnum.values());
                }
                for (ViewEnum view : ViewEnum.values()) {
                    boolean add = true;
                    for (Object obj : dataList) {
                        JSONObject data = (JSONObject) obj;
                        String handler = data.getString("executorHandler");
                        if (view.code.equals(handler)) {
                            String cron = cronMap.get(view.code);
                            //更新执行时间和状态
                            String enabledStatus = "1";
                            if ((cron != null && !cron.equals(data.getString("jobCron"))) ||
                                    !enabledStatus.equals(data.getString("triggerStatus"))) {
                                data.put("jobCron", cron);
                                data.put("triggerStatus", enabledStatus);
                                updateJob(headers, data);
                            }
                            add = false;
                            break;
                        }
                    }
                    if (add) {
                        viewList.add(view);
                    }
                }
            }
        } catch (Exception e) {
            log.error("查询任务列表ID失败: {}", jobGroupId, e);
        }
        return viewList;
    }

    private void updateJob(HttpHeaders headers, JSONObject data) {
        String  apiUrl = adminAddress + "/jobinfo/update";
        MultiValueMap<String,String> jobInfo = new LinkedMultiValueMap<>();
        for (String key : data.keySet()) {
            Object value = data.get(key);
            // 所有值转为字符串（表单只支持字符串）
            jobInfo.add(key, value != null ? value.toString() : "");
        }
        HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(jobInfo, headers);
        // 执行更新
        String jobCode = data.getString("executorHandler");
        try {
            ResponseEntity<Map> response = restTemplate.postForEntity(apiUrl, request, Map.class);
            if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
                log.info("任务更新成功: {}",jobCode);
            }else{
                log.info("任务更新失败: {},{}",  jobCode,response.getStatusCode() );
            }
        } catch (Exception e) {
            log.error("调用XXL-Job API失败: {}", jobCode, e);
        }
    }

    /**
     * 注册或更新单个任务
     */
    private void registerJob(String jobGroupId, ViewEnum jobEnum,HttpHeaders headers ) {
        //  构建任务参数
        MultiValueMap<String, String> jobInfo = buildJobInfo(jobGroupId, jobEnum);
        HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(jobInfo, headers);
        String  apiUrl = adminAddress + "/jobinfo/add";
        // 执行注册
        try {
            ResponseEntity<Map> response = restTemplate.postForEntity(apiUrl, request, Map.class);
            if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
                log.info("任务注册成功: {}",  jobEnum.code);
            }else{
                log.info("任务注册失败: {},{}",  jobEnum.code,response.getStatusCode() );
            }
        } catch (Exception e) {
            log.error("调用XXL-Job API失败: {}", jobEnum.code, e);
        }
    }


    /**
     * 构建任务参数
     */
    private MultiValueMap<String, String> buildJobInfo(String jobGroupId, ViewEnum jobEnum) {
        MultiValueMap<String,String> jobInfo = new LinkedMultiValueMap<>();
        jobInfo.add("jobGroup", jobGroupId);
        jobInfo.add("jobDesc", jobEnum.name());
        jobInfo.add("executorRouteStrategy", "ROUND");
        // 默认每日凌晨0点执行一次
        String cron = cronMap.getOrDefault(jobEnum.code, "0 0 0 * * ?");
        jobInfo.add("cronGen_display",cron );
        jobInfo.add("jobCron", cron);
        jobInfo.add("glueType", "BEAN");
        jobInfo.add("executorHandler", jobEnum.code);
        jobInfo.add("executorBlockStrategy", "SERIAL_EXECUTION");
        jobInfo.add("executorTimeout", "0");
        jobInfo.add("executorFailRetryCount", "1");
        jobInfo.add("author", "AUTO_SYSTEM");
        jobInfo.add("glueRemark", "GLUE代码初始化");
        jobInfo.add("triggerStatus", "1"); // 1-启用, 0-停用
        return jobInfo;
    }

}